﻿
Imports osi.root.constants
Imports osi.root.formation
Imports osi.root.connector
Imports osi.root.procedure
Imports osi.root.utils

Public Class auto_pre_generated_device_pool(Of T)
    Inherits pre_generated_device_pool(Of T)

    Private s As Boolean

    Public Sub New(ByVal max_count As UInt32,
                   ByVal identity As String,
                   Optional ByVal ctor As Func(Of pointer(Of T), event_comb) = Nothing,
                   Optional ByVal auto_generation_check_interval_ms As Int64 = _
                       constants.default_auto_generation_check_interval_ms,
                   Optional ByVal auto_generation_failure_wait_ms As Int64 = _
                       constants.default_auto_generation_failure_wait_ms,
                   Optional ByVal max_concurrent_generations As Int32 = _
                       constants.default_max_concurrent_generations,
                   Optional ByVal validator As Func(Of T, Boolean) = Nothing,
                   Optional ByVal closer As Action(Of T) = Nothing,
                   Optional ByVal device_id As Func(Of T, String) = Nothing,
                   Optional ByVal new_device_inserted_action As Action(Of T) = Nothing)
        MyBase.New(max_count, identity, ctor, validator, closer, device_id, new_device_inserted_action)
        start_auto_generation_procedure(auto_generation_check_interval_ms,
                                        auto_generation_failure_wait_ms,
                                        max_concurrent_generations)
    End Sub

    Public Sub New(ByVal max_count As UInt32,
                   Optional ByVal ctor As Func(Of pointer(Of T), event_comb) = Nothing,
                   Optional ByVal auto_generation_check_interval_ms As Int64 = _
                       constants.default_auto_generation_check_interval_ms,
                   Optional ByVal auto_generation_failure_wait_ms As Int64 = _
                       constants.default_auto_generation_failure_wait_ms,
                   Optional ByVal max_concurrent_generations As Int32 = _
                       constants.default_max_concurrent_generations,
                   Optional ByVal validator As Func(Of T, Boolean) = Nothing,
                   Optional ByVal closer As Action(Of T) = Nothing,
                   Optional ByVal device_id As Func(Of T, String) = Nothing,
                   Optional ByVal new_device_inserted_action As Action(Of T) = Nothing)
        MyBase.New(max_count, ctor, validator, closer, device_id, new_device_inserted_action)
        start_auto_generation_procedure(auto_generation_check_interval_ms,
                                        auto_generation_failure_wait_ms,
                                        max_concurrent_generations)
    End Sub

    Public Function stopped() As Boolean
        Return s
    End Function

    Private Function create_devices(ByVal max_concurrent_generations As Int32) As event_comb
        Dim ec As event_comb = Nothing
        Dim ecs() As event_comb = Nothing
        Dim p() As pointer(Of T) = Nothing
        Return New event_comb(Function() As Boolean
                                  assert(max_concurrent_generations = npos OrElse max_concurrent_generations > 0)
                                  assert(total_count() < mc)
                                  Dim expected As Int32 = 0
                                  expected = If(max_concurrent_generations < 0,
                                                mc - total_count(),
                                                min(max_concurrent_generations, mc - total_count()))
                                  ReDim ecs(expected - 1)
                                  ReDim p(expected - 1)
                                  For i As Int32 = 0 To expected - 1
                                      p(i) = New pointer(Of T)()
                                      ecs(i) = create_valid_device(p(i))
                                  Next
                                  Return waitfor(ecs) AndAlso
                                         goto_next()
                              End Function,
                              Function() As Boolean
                                  assert(array_size(p) = array_size(ecs))
                                  For i As Int32 = 0 To array_size(ecs) - 1
                                      assert(Not p(i) Is Nothing)
                                      If ecs(i).end_result() Then
                                          If Not insert_new_device(+p(i), True) Then
                                              ' should not happen
                                              raise_error(error_type.warning,
                                                          "failed to insert device to ",
                                                          id,
                                                          ", will close the device ",
                                                          device_identity(+p(i)))
                                          End If
                                      End If
                                  Next
                                  Return ecs.end_result() AndAlso
                                         goto_end()
                              End Function)
    End Function

    Private Function auto_generation_procedure(ByVal check_interval_ms As Int64,
                                               ByVal failure_wait_ms As Int64,
                                               ByVal max_concurrent_generations As Int32) As event_comb
        assert(Not stopped())
        Dim ec As event_comb = Nothing
        Return lifetime_event_comb(AddressOf expired,
                                   Function() As Boolean
                                       assert(mc > 0)
                                       assert(check_interval_ms = npos OrElse check_interval_ms > 0)
                                       If check_interval_ms < 0 Then
                                           check_interval_ms = constants.default_auto_generation_check_interval_ms
                                       End If
                                       assert(failure_wait_ms = npos OrElse failure_wait_ms > 0)
                                       If failure_wait_ms < 0 Then
                                           failure_wait_ms = constants.default_auto_generation_failure_wait_ms
                                       End If
                                       Return goto_next()
                                   End Function,
                                   Function() As Boolean
                                       Dim last_succ As Boolean = False
                                       last_succ = ec.end_result_or_null()
                                       ec = Nothing
                                       If last_succ Then
                                           If total_count() < mc Then
                                               ec = create_devices(max_concurrent_generations)
                                               Return waitfor(ec)
                                           Else
                                               Return waitfor(check_interval_ms)
                                           End If
                                       Else
                                           Return waitfor(failure_wait_ms)
                                       End If
                                   End Function)
    End Function

    Private Sub start_auto_generation_procedure(ByVal check_interval_ms As Int64,
                                                ByVal failure_wait_ms As Int64,
                                                ByVal max_concurrent_generations As Int32)
        assert(limited_max_count())
        assert_begin(New event_comb(Function() As Boolean
                                        Return waitfor(auto_generation_procedure(check_interval_ms,
                                                                                 failure_wait_ms,
                                                                                 max_concurrent_generations)) AndAlso
                                               goto_next()
                                    End Function,
                                    Function() As Boolean
                                        s = True
                                        Return goto_end()
                                    End Function))
    End Sub
End Class
